#pragma once

#include "ListControl.h"
#include <map>

namespace My {

class Column;
class ColumnSet;
class Grid;

class Column : 
	private RangeItem 
{
	friend class ColumnSet;
public:
	Column();
public:
	virtual String GetCaption() const
		{ return String(); }
	bool IsVisible() const
		{ return m_Visible; }
	Size GetWidth() const
		{ return RangeItem::GetSize(); }
	Size GetIndex() const
		{ return m_Index; }
	Span GetBounds() const
		{ return RangeItem::GetBounds(); }
	/// If not visible, returns -1
	int GetVisibleIndex() const;
protected:
	ColumnSet * GetColumns() const
		{ return m_pColumns; }
	void SetVisible(bool);
	void SetWidth(Size);
private:
	Size CalcVisibleIndex() const;
private:
	ColumnSet *	m_pColumns;
	int			m_Index;
	bool		m_Visible;
};

class ColumnSet :
	private Range
{
	friend class Column;
public:
	ColumnSet(Grid &);
public:
	Grid & GetGrid() const
		{ return m_Grid; }
	bool IsEmpty() const;
	Size GetColumnCount() const;
	Column & GetColumn(Size) const;
	Size GetVisibleColumnCount() const;
	Column & GetVisibleColumn(Size) const;
	Size GetTotalWidth() const;
	void Append(Column * pColumn)
		{ Insert(GetColumnCount(), pColumn); }
	void Insert(Size pos, Column *);
	void Remove(Column *);
	void Remove(Size pos, Size count = 1);
	void Clear();
protected:
	virtual void InvalidateSpan(Span);
	virtual void SizeChanged();
	virtual int GetOffset() const
		{ return 0; }
private:
	void SetColumnVisible(Column &, bool);
private:
	Grid &					m_Grid;
	std::vector<Column *>	m_Columns;
};

class Grid : public virtual List
{
	friend class ColumnSet;
public:
	Grid(ScrollBox &);
public:
	const ColumnSet & GetColumns() const
		{ return m_Cols; }
	ColumnSet & GetColumns()
		{ return m_Cols; }
protected:
	virtual My::Size GetPreferredWidth() const;
private:
	ColumnSet	m_Cols;
};

class GridRow : 
	public virtual Row,
	public Container
{
	friend class Cell;
public:
	Grid * GetGrid() const;
public:
	virtual void HandlePaint(CDC *, const CRect &);
public:
	virtual CRect GetCellBounds(const Column &) const;
	virtual void PaintCell(CDC *, const CRect & rClip, const Column &, const CRect & rCell);
private:
	void PaintCells(CDC *, const CRect & rClip, const ColumnSet &);
};

class Cell : 
	public virtual Control 
{
	friend class GridRow;
public:
	virtual CRect Bounds() const;
	virtual bool Visible() const;
protected:
	GridRow * GetRow() const;
	virtual Column * GetColumn() const = 0;
};

class GridHeader : public GridRow {
public:
	GridHeader();
	virtual void HandlePaint(CDC *, const CRect &);
	virtual void PaintCell(CDC *, const CRect & rClip, const Column &, const CRect & rCell);
};

class GridBoxWidget : 
	public ScrollBox, 
	public Widget 
{
public:
	GridBoxWidget() : m_Grid(* this) { }
public:
	virtual CRect Bounds() const
		{ return Widget::Bounds(); }
	virtual bool Visible() const
		{ return Widget::Visible(); }
	virtual const CFont * Font() const
		{ return Widget::Font(); }
public:
	Grid & GetGrid() 
		{ return m_Grid; }
private:
	Grid	m_Grid;
};

} // My